package database

import (
	"fmt"
	"github.com/rs/zerolog/log"
	uuid "github.com/satori/go.uuid"
	"strings"
	"time"

	"h8QuestionnaireServer/components/config"

	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/postgres"
)

var db *gorm.DB

type Model struct {
	Id        string
	IsDelete  int       `gorm:"column:is_delete"`
	CreatedAt *time.Time `gorm:"column:created_at"`
	UpdatedAt *time.Time `gorm:"column:updated_at"`
	DeletedAt *time.Time `gorm:"column:deleted_at"`
}

//func registerEntity() {
//	err := db.AutoMigrate(&entity.DictEmployee{}).Error
//	log.Printf("registering result %v.", err)
//}

func init() {
	dbStr := fmt.Sprintf("host=%s port=%s user=%s dbname=%s sslmode=disable password=%s",
		config.Config.DB.Ip, config.Config.DB.Port, config.Config.DB.Name, config.Config.DB.Schema,
		config.Config.DB.Password)
	log.Info().Msgf("db url %s.", dbStr)
	var err error
	db, err = gorm.Open("postgres", dbStr)
	if err != nil {
		log.Error().Msgf("connection error %v", err)
		panic(err)
	} else {
		log.Info().Msgf("database connected")
	}

	db.Callback().Create().Before("gorm:create").Register("before_create", createCallback)
	db.Callback().Update().Before("gorm:update").Register("before_update", updateCallback)
	db.Callback().Delete().Before("gorm:delete").Register("before_delete", deleteCallback)
	db.DB().SetMaxIdleConns(10)
	db.DB().SetMaxOpenConns(100)

	//registerEntity()
}

// createCallback will set `CreatedAt`, `UpdatedAt` when creating
func createCallback(scope *gorm.Scope) {
	if !scope.HasError() {
		nowTime := time.Now()
		if idField, ok := scope.FieldByName("Id"); ok {
			if idField.IsBlank {
				id := strings.Replace(uuid.NewV1().String(), "-", "", -1)
				idField.Set(id)
			}
		}

		if createTimeField, ok := scope.FieldByName("CreatedAt"); ok {
			if createTimeField.IsBlank {
				createTimeField.Set(nowTime)
			}
		}

		if modifyTimeField, ok := scope.FieldByName("UpdatedAt"); ok {
			if modifyTimeField.IsBlank {
				modifyTimeField.Set(nowTime)
			}
		}

		if idDeleteField, ok := scope.FieldByName("IsDelete"); ok {
			if idDeleteField.IsBlank {
				idDeleteField.Set(0)
			}
		}

		if deletedAtField, ok := scope.FieldByName("DeletedAt"); ok {
			deletedAtField.Set(nil)
		}
	}
}

// updateCallback will set `ModifiedOn` when updating
func updateCallback(scope *gorm.Scope) {
	modifyTimeField, ok := scope.FieldByName("UpdatedAt")
	if ok {
		modifyTimeField.Set(time.Now())
	}
}

func deleteCallback(scope *gorm.Scope) {
	if idDeleteField, ok := scope.FieldByName("IsDelete"); ok {
		if idDeleteField.IsBlank {
			idDeleteField.Set(1)
		}
	}
}

func GetPostgreDB() *gorm.DB {
	return db
}
